/*
 * Copyright 2012 Adrian Sulumberchean

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

package ro.sands.requests.android.server;

import org.json.JSONException;
import org.json.JSONObject;

import ro.sands.requests.android.tools.ErrorCodesMap;
import ro.sands.requests.android.tools.Util;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

/**
 * 
 * Callback class for receiving responses from the server
 * 
 * @author Adrian Sulumberchean
 */

public abstract class AResponse implements IResponseListener{

	private JSONObject response;
	private String id = "-";  						// request/error id
	protected String requestID = "";
	private String errorMessage;
	private String url;
	protected boolean showMessages = false;
	
	//this handler sends a message from a background thread to UI thread
	private static Handler handler = new Handler(){

		public void handleMessage(Message msg) {
			AResponse responseClass = (AResponse) msg.obj;
			
			int responseStatus = msg.arg1;		
			Bundle msgData = msg.getData();
			String id = msgData.getString(ID_TAG); 	// request/error id
			
			switch (responseStatus) {
			case SUCCESS:	try {
								responseClass.onSuccessInMainThread(id, responseClass.getResponse());
							} catch (JSONException e) {
								Util.log("", e);
							}
							break;
							
			case ERROR: responseClass.onFailureInMainThread(id);
						break;
			case ERROR_WITH_MESSAGE: 
				String message = msgData.getString(ERROR_MESSAGE_ID_TAG);
				String url = msgData.getString(URL_ID_TAG);

				responseClass.onFailureWithMessageInMainThread(id, message, url);
				break;
			default:
				break;
			}
		}
	};
	
	public static final String STATUS_TAG = "ST";
	public static final String ERROR_MESSAGE_ID_TAG = "MS";
	public static final String URL_ID_TAG = "AD";
	public static final String SM_ID_TAG = "SM";
	public static final String VM_ID_TAG = "VM";
	public static final String WM_ID_TAG = "WM";
	
	public static final String OK_STATUS = "ok";
	public static final String ID_TAG = "ID";
	
	private static final int SUCCESS = 1;
	private static final int ERROR = 0;
	private static final int ERROR_WITH_MESSAGE = 2;
	
	// methods handled in the background thread
	public abstract void onSuccess(String requestId, JSONObject response) throws JSONException;
	public abstract void onFailure(String errorId);
	public void onFailureWithMessage(String errorId, String message, String url) {}
	//---------------------------------------------
	
	// methods handled in the main thread
	protected void onSuccessInMainThread(String requestId, JSONObject response) throws JSONException{}
	protected void onFailureInMainThread(String errorId){}
	protected void onFailureWithMessageInMainThread(String errorId, String message, String url){}
	//----------------------------------------------
	
	
	/**
	 *	Overide onSuccessInMainThread to handle the response in the Main thread
	 */
	public void doSuccessInMainThread() {
		sendMessageToHandler(SUCCESS);
	}
	
	/**
	 *	Overide onFailureInMainThread to handle the response error in the Main thread
	 */
	public void doFailureInMainThread() {
		sendMessageToHandler(ERROR);
	}
	
	/**
	 *	Overide onFailureInMainThread to handle the response error in the Main thread
	 */
	public void doFailureWithMessageInMainThread() {
		sendMessageToHandler(ERROR_WITH_MESSAGE);
	}
	
	/*
	 * Sends a message to handler where arg1 will be the response STATUS (SUCCESS or ERROR), 
	 * arg2 will be the error/request ID and obj will be the response class
	 * 
	 * @param status - SUCCESS/ERROR (1/0) 
	 */
	private void sendMessageToHandler(int status){
		Message msg = Message.obtain();
		
		msg.arg1 = status;
		
		Bundle data = new Bundle();
		data.putString(ID_TAG, getId());
		
		if(status == ERROR_WITH_MESSAGE){
			data.putString(ERROR_MESSAGE_ID_TAG, errorMessage);
			data.putString(URL_ID_TAG, url);
		}
		
		msg.setData(data);
		msg.obj = this;
		
		handler.sendMessage(msg);
	}
	
	public void responseReceived(String requestId, String jsonResponse) {
		try {
			id = requestId;
			
			response = new JSONObject(jsonResponse);
			
			String responseStatus = response.getString(STATUS_TAG);
			
			if(OK_STATUS.equalsIgnoreCase(responseStatus)){
				onSuccess(id, response);
			}
			else{
				// error could be handled in this class as well but then you won't know for what request camed the error
				id = response.getString(ERROR_MESSAGE_ID_TAG);
				
				this.requestID = requestId;
				
				errorMessage = ErrorCodesMap.getInstance().getErrorMessage(id);
				url = "";
				
				if(response.isNull(URL_ID_TAG) && response.isNull(SM_ID_TAG) && response.isNull(VM_ID_TAG) && response.isNull(WM_ID_TAG)){
					onFailure(id);
					manageError(id);
					return;
				}
				else if(!response.isNull(SM_ID_TAG)){
					errorMessage = response.optString(SM_ID_TAG);
				}
				else if(!response.isNull(VM_ID_TAG)){
					errorMessage = response.optString(VM_ID_TAG);
				}
				else if(!response.isNull(WM_ID_TAG)){
					errorMessage = response.optString(WM_ID_TAG);
				}
				
				if(!response.isNull(URL_ID_TAG)){
					url = response.optString(URL_ID_TAG);
				}
				
				manageError(id);
				onFailureWithMessage(id, errorMessage, url);
			}
		} catch (JSONException e) {
			Util.log("the request id was: " + requestId, e);
		} 
	}
	
	private void manageError(String errorId){
		if(showMessages){
			sendMessageToHandler(ERROR_WITH_MESSAGE);
		}
	}
	
	/**
	 * @return the response
	 */
	public JSONObject getResponse() {
		return response;
	}
	
	public void setResponse(JSONObject response) {
		this.response = response;
	}
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	
	public String getRequestID() {
		return requestID;
	}
	public void setRequestID(String requestID) {
		this.requestID = requestID;
	}
}
